/////////////////////////////////////////////////////////////////////
//
//  MOE Framework (Meta Object Encapsulation Framework)
//
//  Original Author: Wiksy Wang, 2011
//
/////////////////////////////////////////////////////////////////////

#include "ClassMeta.h"

namespace MOE
{

ClassMeta::ClassMeta(const ClassIDType classID, const RawByteVector& className, const size_t classSize, const AtomTypes atomType)
	: _metaClassID(classID)
	, _metaClassName(className)
	, _classSize(classSize)
	, _atomType(atomType)
{
}

bool ClassMeta::IsAtomClass() const
{
	return (_atomType != AT_NonAtom);
}

bool ClassMeta::Set(Address object, const RawByteVector& field, ConstAddress data) const
{
	DataMemberMap::const_iterator it = _dataMembers.find(field);
	if (it == _dataMembers.end() || !it->second.HasSetter())
	{
		return false;
	}
	else
	{
		it->second.Set(object, data);
		return true;
	}
}

bool ClassMeta::Get(Address object, const RawByteVector& field, Address data) const
{
	DataMemberMap::const_iterator it = _dataMembers.find(field);
	if (it == _dataMembers.end() || !it->second.HasGetter())
	{
		return false;
	}
	else
	{
		it->second.Get(object, data);
		return true;
	}
}

bool ClassMeta::Access(Address object, const RawByteVector& field, Address* pDataAddr) const
{
	DataMemberMap::const_iterator it = _dataMembers.find(field);
	if (it == _dataMembers.end() || !it->second.HasDirectAccess())
	{
		return false;
	}
	else
	{
		*pDataAddr = it->second.DirectAccess(object);
		return true;
	}
}

const DataMemberMeta& ClassMeta::Member(const RawByteVector& field) const
{
	DataMemberMap::const_iterator it = _dataMembers.find(field);
	if (it == _dataMembers.end())
	{
		return DataMemberMeta::InvalidMember;
	}
	else
	{
		return it->second;
	}
}

ClassMeta& ClassMeta::operator<<(const Assign::AssignProxy& proxy)
{
	_dataMembers[proxy._name] = proxy._memberDef;
	return *this;
}

ClassMeta& ClassMeta::DefineConstructor(const DefaultConstructorFuncType& constructor)
{
	_defaultConstructor = constructor;
	return *this;
}

ClassMeta& ClassMeta::DefineDestructor(const DestructorFuncType& destructor)
{
	_destructor = destructor;
	return *this;
}

Address ClassMeta::New() const
{
	if (_defaultConstructor)
	{
		return _defaultConstructor();
	}
	else
	{
		return new char[_classSize];
	}
}

void ClassMeta::Delete(Address object) const
{
	if (_destructor)
	{
		_destructor(object);
	}
	else
	{
		delete [] static_cast<char*>(object);
	}
}

}
